package com.gserver.commons.script;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Map;

import javax.script.Bindings;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleBindings;

import com.google.common.io.Files;

public class ScriptManager implements IScriptEngine {

	/**
	 * 
	 * @param charset
	 * @param engineName
	 *            javascript jython
	 */
	public ScriptManager(String charset, String engineName) {
		this.charset = Charset.forName(charset);
		ScriptEngineManager factory = new ScriptEngineManager();
		engine = factory.getEngineByName(engineName);
	}

	public Object runScript(Map binding, String scriptFile, String charset) {
		String content = null;
		try {
			Bindings _bindings = new SimpleBindings(binding);
			content = Files.toString(new File(scriptFile),
					charset == null ? this.charset : Charset.forName(charset));
			return engine.eval(content, _bindings);
		} catch (IOException e) {
			throw new RuntimeException("FILE.ERR.IO.FAILE Throw Exception", e);
		} catch (ScriptException se) {
			throw new RuntimeException("SCRIPT.ERR.EXE.FAIL Throw Exception"
					+ (new StringBuilder(String.valueOf(scriptFile)))
							.append(" content:").append(content).toString(), se);
		}
	}

	public Object runScript(Map binding, String scriptContent) {
		Bindings _bindings;
		try {
			if (binding == null || binding.isEmpty())
				return engine.eval(scriptContent);
			_bindings = new SimpleBindings(binding);
			return engine.eval(scriptContent, _bindings);
		} catch (ScriptException se) {
			throw new RuntimeException("SCRIPT.ERR.EXE.FAIL Throw Exception",
					se);
		}
	}

	public String getScriptContent(String scriptFile) {
		return getScriptContent(scriptFile, charset.name());

	}

	public String getScriptContent(String scriptFile, String charset) {
		try {
			String path = Thread.currentThread().getContextClassLoader()
					.getResource(scriptFile).getPath();
			return Files.toString(new File(path),
					charset == null ? this.charset : Charset.forName(charset));
		} catch (IOException e) {
			throw new RuntimeException("FILE.ERR.IO.FAILE Throw Exception", e);
		}
	}

	public boolean doLogicEval(Map binding, String exp) {
		if (exp == null || exp.length() == 0)
			throw new IllegalArgumentException(
					"\u6761\u4EF6\u8868\u8FBE\u5F0F\u4E0D\u80FD\u4E3A\u7A7A");
		try {
			Bindings _bindings = new SimpleBindings(binding);
			Object _ret = engine.eval(exp, _bindings);
			if (_ret instanceof Boolean)
				return ((Boolean) _ret).booleanValue();
		} catch (ScriptException se) {
			throw new RuntimeException("SCRIPT.ERR.EXE.FAIL Throw Exception"
					+ exp, se);
		}
		throw new RuntimeException(
				(new StringBuilder(
						"\u65E0\u6548\u7684\u903B\u8F91\u8FD0\u7B97\u8868\u8FBE\u5F0F:"))
						.append(exp).toString());
	}

	public double doMathEval(Map binding, String exp) {
		if (exp == null || exp.length() == 0)
			throw new IllegalArgumentException(
					"\u6761\u4EF6\u8868\u8FBE\u5F0F\u4E0D\u80FD\u4E3A\u7A7A");
		try {
			Bindings _bindings = new SimpleBindings(binding);
			Object _ret = engine.eval(exp, _bindings);
			if (_ret instanceof Number)
				return ((Number) _ret).doubleValue();
		} catch (ScriptException se) {
			throw new RuntimeException("SCRIPT.ERR.EXE.FAIL Throw Exception:"
					+ exp, se);
		}
		throw new RuntimeException(
				(new StringBuilder(
						"\u65E0\u6548\u7684\u903B\u8F91\u8FD0\u7B97\u8868\u8FBE\u5F0F:"))
						.append(exp).toString());
	}

	private final Charset charset;
	private final ScriptEngine engine;

}
